<?php
class Logger
{
	const TRACE_LEVEL = 0;
	const DEBUG_LEVEL = 1;
	const INFO_LEVEL = 2;
	const WARN_LEVEL = 3;
	const ERROR_LEVEL = 4;
	const FATAL_LEVEL = 5;
	const ANALYTIC_LEVEL = 6;

	const MAX_BUF_SIZE = 2048;
	const DEFAULT_COST_NAME = "__default__";

	private static $loggerCache = array();
	
	private static $fp;

	private $name = "NULL";
	private $method = "NULL";
	public $actor = 0;
	private $host = "0.0.0.0";
	private $baseInfo;

	private $customFields = false;
	
	private $costs = array(DEFAULT_COST_NAME=>0);

	private static $level = INFO_LEVEL;
	private static $levelName = "INFO";
	private static $buf = "";

	private static $mailTo = "";

	private function __construct($name) {
		$this->name = $name;
		if (isset($_COOKIE['bid'])) {
			$this->actor = $_COOKIE['bid'];
		}

		if (isset($_SERVER['REMOTE_ADDR'])) {
			$this->host = $_SERVER['REMOTE_ADDR'];
		}
	}
	
	public static function configure($config_path,$params=NULL) {
		require($config_path);
		$path = $mainConfig["log_path"];
		$level = $mainConfig["log_level"];
		$prefix = $mainConfig["log_prefix"];
		
		self::$mailTo = $mainConfig["webmaster"];
		
		if ($params) {
			if (isset($params["log_path"])) $path = $params["log_path"];
			if (isset($params["log_level"])) $level = $params["log_level"];
			if (isset($params["log_prefix"])) $prefix = $params["log_prefix"];
		}
		
		$fileName = $path."/$prefix-".strftime("%Y-%m-%d").".log";
		self::$fp = @fopen($fileName, "ab");
		self::$level = $level;
		register_shutdown_function("__closeRssreaderLog");
	}
	
	
	private static function getLevelNameFromLevel($level) {
		$name = "UNKNOWN";
		switch ($level) {
			case self::TRACE_LEVEL:
				$name="TRACE";
				break;
			case self::DEBUG_LEVEL:
				$name = "DEBUG";
				break;
			case self::INFO_LEVEL:
				$name = "INFO";
				break;
			case self::WARN_LEVEL:
				$name = "WARN";
				break;
			case self::ERROR_LEVEL:
				$name = "ERROR";
				break;
			case self::FATAL_LEVEL:
				$name = "FATAL";
				break;
			case self::ANALYTIC_LEVEL:
				$name = "ANALYTIC";
				break;
		}
		return $name;
	}

	/**
	 * @return Logger log
	 */
	public static function getLogger($name) {
		if (!isset(self::$loggerCache[$name])) {
			self::$loggerCache[$name] = new Logger($name);
		}
		return self::$loggerCache[$name];
	}
	
	public static function analytic($name,$params,$actorId=0){
		$logger = self::getLogger("analytic");
		if($actorId){
			$logger->actor = $actorId;
		}
		$logger->_analytic($name,$params);
	}
	private function _analytic($name,$params){
		$msg = "name=[$name]";
		foreach($params as $key=>$value){
			if ($value===true){
				$value = 'true';
			} elseif($value ===false){
				$value = 'false';
			}
			$msg .= " $key=[$value]";
		}
		self::writeLog(self::ANALYTIC_LEVEL, $msg, 0);
	}

	public function setMethod($method) {
		$this->method = $method;
	}
	
	public function clearMethod() {
		$this->method = "NULL";
	}

	public function setCustomField($fields) {
		if ($fields){
			$this->customFields = $fields;
		}
	}
	
	public static function isTraceEnabled() {
		return self::$level <= self::TRACE_LEVEL;
	}

	public static function isDebugEnabled() {
		return self::$level <= self::DEBUG_LEVEL;
	}

	public static function isInfoEnabled() {
		return self::$level <= self::INFO_LEVEL;
	}

	public static function isWarnEnabled() {
		return self::$level <= self::WARN_LEVEL;
	}

	public static function isErrorEnabled() {
		return self::$level <= self::ERROR_LEVEL;
	}

	public static function isFatalEnabled() {
		return self::$level <= self::FATAL_LEVEL;
	}

	public function trace($msg) {
		if (self::isTraceEnabled()) {
			self::writeLog(self::TRACE_LEVEL, $msg, 0);
		}
	}

	
	public function debug($msg) {
		if (self::isDebugEnabled()) {
			self::writeLog(self::DEBUG_LEVEL, $msg, 0);
		}
	}

	public function info($msg) {
		if (self::isInfoEnabled()) {
			self::writeLog(self::INFO_LEVEL, $msg, 0);
		}
	}

	public function warn($msg) {
		if (self::isWarnEnabled()) {
			self::writeLog(self::WARN_LEVEL, $msg, 0);
		}
	}

	public function error($msg) {
		if (self::isErrorEnabled()) {
			self::writeLog(self::ERROR_LEVEL, $msg, 0);
		}
	}

	public function fatal($msg,$title=NULL) {
		if (self::isFatalEnabled()) {
			self::writeLog(self::FATAL_LEVEL, $msg, 0);
			try{
				//如果指定了收件人
				if (self::$mailTo){
					if (!$title){
						$title = substr($msg,0,50);
						$title = preg_replace('/[\r\n\s]+/',"",$title);
					}
					$host = explode(".",$_SERVER["SERVER_NAME"]);
					if ($host) $title.="(".$host[0].")";
					$headers = "From: bug@topgene.net";
					$title = "=?UTF-8?B?".base64_encode($title)."?=";
					$msg = mb_convert_encoding($msg,"gbk","UTF-8");
					$ret = mail(self::$mailTo,$title,$msg,$header);
				}
			}catch(Exception $ex){}
		}
	}

	public function start() {
		$this->costs[self::DEFAULT_COST_NAME] = microtime(true);
	}

	public function trace_end($msg) {
		if (self::isTraceEnabled()) {
			$cost = intval((microtime(true) - $this->costs[self::DEFAULT_COST_NAME]) * 1000);
			self::writeLog(self::TRACE_LEVEL, $msg, $cost);
		}
	}

	public function debug_end($msg) {
		if (self::isDebugEnabled()) {
			$cost = intval((microtime(true) - $this->costs[self::DEFAULT_COST_NAME]) * 1000);
			self::writeLog(self::DEBUG_LEVEL, $msg, $cost);
		}
	}

	public function info_end($msg) {
		if (self::isInfoEnabled()) {
			$cost = intval((microtime(true) - $this->costs[self::DEFAULT_COST_NAME]) * 1000);
			self::writeLog(self::INFO_LEVEL, $msg, $cost);
		}
	}

	public function warn_end($msg) {
		if (self::isWarnEnabled()) {
			$cost = intval((microtime(true) - $this->costs[self::DEFAULT_COST_NAME]) * 1000);
			self::writeLog(self::WARN_LEVEL, $msg, $cost);
		}
	}

	public function error_end($msg) {
		if (self::isErrorEnabled()) {
			$cost = intval((microtime(true) - $this->costs[self::DEFAULT_COST_NAME]) * 1000);
			self::writeLog(self::ERROR_LEVEL, $msg, $cost);
		}
	}

	public function fatal_end($msg) {
		if (self::isFatalEnabled()) {
			$cost = intval((microtime(true) - $this->costs[self::DEFAULT_COST_NAME]) * 1000);
			self::writeLog(self::FATAL_LEVEL, $msg, $cost);
		}
	}

	public function start_with($name) {
		$this->costs[$name] = microtime(true);
	}


	public function trace_end_with($name, $msg) {
		if (self::isTraceEnabled()) {
			$cost = intval((microtime(true) - $this->costs[$name]) * 1000);
			self::writeLog(self::TRACE_LEVEL, $msg, $cost);
		}
	}

	public function debug_end_with($name, $msg) {
		if (self::isDebugEnabled()) {
			$cost = intval((microtime(true) - $this->costs[$name]) * 1000);
			self::writeLog(self::DEBUG_LEVEL, $msg, $cost);
		}
	}

	public function info_end_with($name, $msg) {
		if (self::isInfoEnabled()) {
			$cost = intval((microtime(true) - $this->costs[$name]) * 1000);
			self::writeLog(self::INFO_LEVEL, $msg, $cost);
		}
	}

	public function warn_end_with($name, $msg) {
		if (self::isWarnEnabled()) {
			$cost = microtime(true) - $this->costs[$name];
			self::writeLog(self::WARN_LEVEL, $msg, $cost);
		}
	}

	public function error_end_with($name, $msg) {
		if (self::isErrorEnabled()) {
			$cost = intval((microtime(true) - $this->costs[$name]) * 1000);
			self::writeLog(self::ERROR_LEVEL, $msg, $cost);
		}
	}

	public function fatal_end_with($name, $msg) {
		if (self::isFatalEnabled()) {
			$cost = intval((microtime(true) - $this->costs[$name]) * 1000);
			self::writeLog(self::FATAL_LEVEL, $msg, $cost);
		}
	}

	private function writeLog($level, $msg, $cost) {
		$levelName = self::getLevelNameFromLevel($level);
		$dateTime = self::getDateTime();
		$host = $this->host;
		$actor = $this->actor;
		$name = $this->name;
		$method = $this->method;
		$customInfo = "";
		if ($this->customFields && is_array($this->customFields)){
			$customInfo = implode(" ",$this->customFields)." ";
		}
		
		self::writeBuf("[$levelName] $dateTime $host $actor $cost $name $method ".$customInfo."$msg");
	}

	private static function getDateTime() {
		return strftime("%Y-%m-%d %H:%M:%S",time());
	}

	private static function writeBuf($msg) {
		self::$buf .= $msg."\n";
		if (strlen(self::$buf) > self::MAX_BUF_SIZE) {
			self::flushLogBuf();
		}
	}

	private static function flushLogBuf() {
		if (strlen(self::$buf) > 0) {
			@fwrite(self::$fp, self::$buf);
			self::$buf = "";
		}
	}

	public static function close() {
		self::flushLogBuf();
		@fflush(self::$fp);
		@fclose(self::$fp);
	}
}

function __closeRssreaderLog()
{
	Logger::close();
}

?>